#!/user/bin/env python
# -*- coding: utf-8 -*-
''' 
Author: Sjy
Description:  当前模块自带简单的工程管理功能
1. 在指定目录下创建对应工程的文件夹
2. 系统默认存在一个默认工程文件夹,允许用户创建,切换,删除工程
3. 每个工程文件夹下管理着不同模块的对应的参数化文件,注意此参数化文件不是提供给用户的,提供给用户的会为用户单独输出
4. 每个工程的文件夹内的数据不互通,但是允许在创建时拷贝数据.
5. 工程目录在的配置信息在当前模块的 config.json 中配置.默认的路径是data/ipimas_projects/ 下面


"repair_scheme_strength": "repair_scheme_strength.json",  # 维修方案强度分析
"extreme_load": "extreme_load.json", # 极限受载分析
"repair_scheme": "repair_scheme.json", # 维修方案优化
"database": "database.json", # 数据库文件
database = {
        "compositePly": [], # 层合板
        "honeycombCore": [], # 蜂窝
        "adhesiveLayer": [], # 胶层
        "metal": [], # 金属
    }

注意 数据库文件是各个工程通用的因此要单独放置
'''

__all__= []

import os
import copy 

import json
import shutil
from typing import Optional, List, Dict
from datetime import datetime
from pydantic import BaseModel, Field, validator
from pathlib import Path

import gui.controls.envs as envs

PATH_PROJECTS = "projects"
FILE_CONFIG = f"{PATH_PROJECTS}/config.json"
FILE_DB = f"{PATH_PROJECTS}/database.json"

class ProjectConfig(BaseModel):
    """工程配置模型"""
    name: str = Field(..., description="工程名称")
    path: str = Field(..., description="工程路径")
    created_at: datetime = Field(default_factory=datetime.now, description="创建时间")
    description: Optional[str] = Field(None, description="工程描述")

    @validator('name')
    def validate_name(cls, v):
        if not v.strip():
            raise ValueError("工程名称不能为空")
        if len(v) > 50:
            raise ValueError("工程名称长度不能超过50个字符")
        return v.strip()

    @validator('path')
    def validate_path(cls, v):
        if not os.path.exists(v):
            raise ValueError("工程路径不存在")
        return v

class ProjectManager:
    """工程管理器（单例模式）"""
    _instance = None
    _initialized = False

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(ProjectManager, cls).__new__(cls)
        return cls._instance

    def __init__(self):
        if not self._initialized:
            self._initialized = True
            self._config_file = FILE_CONFIG
            self._projects: Dict[str, ProjectConfig] = {}
            self._current_project: Optional[str] = None
            self._db = {} # 工程数据 格式是 [工程名]= {数据字典} 注意这里是缓存 每次保存的时候都要将各个模块的数据保存到指定位置
            self._load_config()
            self._load_db()

    def _load_config(self):
        """加载配置文件"""
        if os.path.exists(self._config_file):
            with open(self._config_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
                self._projects = {name: ProjectConfig(**config) for name, config in data.get('projects', {}).items()}
                self._current_project = data.get('current_project')
        # 注意 如果没有 当前工程则默认设置第一个 如果第一个没有则默认存在一个
        if not self._current_project and self._projects:
            self._current_project = list(self._projects.keys())[0]
        if not self._current_project and not self._projects:
            self._current_project = "default"
            self.create_project("default", "系统默认工程")
            
    def _load_db(self):
        """加载工程数据
            1. 根据当前工程去找对应的工程文件夹 
            
        """
        moduleFileMaps = {
            "repair_scheme_strength": "repair_scheme_strength.json",  # 维修方案强度分析
            "extreme_load": "extreme_load.json", # 极限受载分析
            "repair_scheme": "repair_scheme.json", # 维修方案优化
            # "database": "database.json", # 数据库文件
        }

        # 注意数据库特殊 数据库不跟工程走，因此他是放在固定位置的
        self._db["database"] = {}
        if os.path.exists(FILE_DB):
            self._db["database"] = envs.UFile.open_json(FILE_DB) or {}

        project_path = self._projects[self._current_project].path 
        for module, file in moduleFileMaps.items(): 
            path = f"{project_path}/{file}"
            if os.path.exists(path):
                try:
                    self._db[module] = envs.UFile.open_json(path)
                except Exception as e:
                    print(f"加载工程数据失败: {e}")
            else:
                self._db[module] = {}   

    def _save_config(self):
        """保存配置文件"""
        data = {
            'projects': {name: project.dict() for name, project in self._projects.items()},
            'current_project': self._current_project
        }
        envs.UFile.save_json(self._config_file, data)

    def create_project(self, name: str, description: Optional[str] = None, copy_from: Optional[str] = None) -> ProjectConfig:
        """创建新工程"""
        if name in self._projects:
            raise ValueError(f"工程 '{name}' 已存在")
        


        # 创建工程目录  注意是相对路径
        project_path = f"{PATH_PROJECTS}/{name}"
        os.makedirs(project_path, exist_ok=True)

        # 创建工程配置
        project = ProjectConfig(
            name=name,
            path=project_path,
            description=description,
        )

        # 如果指定了复制源工程，则复制数据
        if copy_from and copy_from in self._projects:
            source_path = self._projects[copy_from].path
            for item in os.listdir(source_path):
                s = os.path.join(source_path, item)
                d = os.path.join(project_path, item)
                if os.path.isdir(s):
                    shutil.copytree(s, d)
                else:
                    shutil.copy2(s, d)

        self._projects[name] = project
        self._save_config()
        return project

    def delete_project(self, name: str) -> None:
        """删除工程"""
        if name not in self._projects:
            raise ValueError(f"工程 '{name}' 不存在")
        # default 工程不能删除 至少保留一个 
        if name == "default":
            raise ValueError("default 工程不能删除 至少保留一个")
        # 如果当前工程是删除的工程 则切换到其他工程
        if self._current_project == name:
            self._current_project = list(self._projects.keys())[0]

        # 删除工程目录
        project_path = self._projects[name].path
        if os.path.exists(project_path):
            shutil.rmtree(project_path)

        del self._projects[name]
        self._save_config()

    def switch_project(self, name: str) -> None:
        """切换当前工程"""
        if name not in self._projects:
            raise ValueError(f"工程 '{name}' 不存在")
        self._current_project = name
        self._save_config()

    def get_current_project(self) -> Optional[ProjectConfig]:
        """获取当前工程配置"""
        if self._current_project:
            return self._projects[self._current_project]
        return None

    def get_all_projects(self) -> List[ProjectConfig]:
        """获取所有工程配置"""
        return list(self._projects.values())

    def update_project(self, name: str, **kwargs) -> ProjectConfig:
        """更新工程配置"""
        if name not in self._projects:
            raise ValueError(f"工程 '{name}' 不存在")

        project = self._projects[name]
        for key, value in kwargs.items():
            if hasattr(project, key):
                setattr(project, key, value)

        self._save_config()
        return project
    

    def get_project_data(self, name: str) -> dict:
        """获取工程数据"""
        name = name or self._current_project
        if name not in self._projects:
            raise ValueError(f"工程 '{name}' 不存在")
        data = {}
        for item in os.listdir(self._projects[name].path):
            s = os.path.join(self._projects[name].path, item)
            if os.path.isdir(s):
                data[item] = s
            else:
                data[item] = s
        return data
    

    # 极限受载分析 extreme_load 数据存取
    def get_extreme_load_data(self) -> dict:
        """获取当前工程极限受载分析数据"""
        return copy.deepcopy(self._db.get("extreme_load", {}))
    def set_extreme_load_data(self, data: dict) -> None:
        """设置当前工程极限受载分析数据"""
        self._db["extreme_load"] = data
    def update_extreme_load_data(self, data: dict) -> None:
        """更新当前工程极限受载分析数据"""
        cur = self.get_extreme_load_data() or {}
        cur.update(data)
        self._db["extreme_load"] = cur
    def save_extreme_load_data(self) -> None:
        """保存当前工程极限受载分析数据"""
        file = f"{self._projects[self._current_project].path}/extreme_load.json"
        envs.UFile.save_json(file, self.get_extreme_load_data())



    # 维修方案强度分析 repair_scheme_strength 数据存取
    def get_repair_scheme_strength_data(self) -> dict:
        """获取当前工程维修方案强度分析数据"""
        return copy.deepcopy(self._db.get("repair_scheme_strength", {}))
    def set_repair_scheme_strength_data(self, data: dict) -> None:
        """设置当前工程维修方案强度分析数据"""
        self._db["repair_scheme_strength"] = data
    def update_repair_scheme_strength_data(self, data: dict) -> None:
        """更新当前工程维修方案强度分析数据"""
        cur = self.get_repair_scheme_strength_data() or {}
        cur.update(data)
        self._db["repair_scheme_strength"] = cur
    def save_repair_scheme_strength_data(self) -> None:
        """保存当前工程维修方案强度分析数据"""
        file = f"{self._projects[self._current_project].path}/repair_scheme_strength.json"
        envs.UFile.save_json(file, self.get_repair_scheme_strength_data())

    
    # 维修方案优化 repair_scheme 数据存取
    def get_repair_scheme_data(self) -> dict:
        """获取当前工程维修方案优化数据"""
        return copy.deepcopy(self._db.get("repair_scheme", {}))
    def set_repair_scheme_data(self, data: dict) -> None:
        """设置当前工程维修方案优化数据"""
        self._db["repair_scheme"] = data
    def update_repair_scheme_data(self, data: dict) -> None:
        """更新当前工程维修方案优化数据"""
        cur = self.get_repair_scheme_data() or {}
        cur.update(data)
        self._db["repair_scheme"] = cur
    def save_repair_scheme_data(self) -> None:
        """保存当前工程维修方案优化数据"""
        file = f"{self._projects[self._current_project].path}/repair_scheme.json"
        envs.UFile.save_json(file, self.get_repair_scheme_data())   

    # 数据库 database 数据存取
    def get_database_data(self) -> dict:
        """获取当前工程数据库数据
        """
        return copy.deepcopy(self._db.get("database", {}))
    # 获取指定类型数据库数据
    def get_database_data_by_type(self, dbType: str) -> dict:
        """获取当前工程指定类型数据库数据"""
        return copy.deepcopy(self.get_database_data().get(dbType, []))
    def set_database_data_by_type(self, dbType: str, data: dict, save: bool = True) -> None:
        """设置当前工程指定类型数据库数据"""
        self._db["database"][dbType] = data
        if save:
            self.save_database_data()
    def save_database_data(self) -> None:
        """保存当前工程数据库数据"""
        envs.UFile.save_json(FILE_DB, self.get_database_data())


# 导出单例实例
project_manager = ProjectManager()

